#include "StdAfx.h"
#include "PUDData.h"
#include <string.h>

PUDData::PUDData(void)
{
	SDUData sduDataNew;
	this->destinationAddress = 0;
	this->sourceAddress = 0;
	this->isCompressed = false;
	this->isEncrypted = false;
	this->functionCode = -1;
	this->PUDLength = 0;
	this->sduDataBody = sduDataNew; 
	this->CRC16 = 0;
	isDataRightByCRC16 = true;
	strcpy(this->szFrame, "");
}

PUDData::~PUDData(void)
{
}

void PUDData::toBinaryDisplay(char* szPUDDataDisplay)
{
	char szDataStringForCRC16[PUDDATA_LENGTH-CRC16_LENGTH+1] = "";
	char szDesAddress[ADDRESS_LENGTH+1] = "";
	char szSrcAddress[ADDRESS_LENGTH+1] = "";
	char szIsCompressed[BOOL_TYPE_SIZE+1] = "";
	char szIsEncrypted[BOOL_TYPE_SIZE+1] = "";
	char szFunctionCode[FUNCTION_CODE_LENGTH+1] = "";
	char szPUDLength[PUDLENGTH_LENGTH+1] = "";
	char szSDUData[SDUDATA_LENGTH+1] = "";
	char szCRC16[CRC16_LENGTH+1] = "";

	szDesAddress[ADDRESS_LENGTH] = '\0';
	szSrcAddress[ADDRESS_LENGTH] = '\0';
	
	szDataStringForCRC16[PUDDATA_LENGTH-CRC16_LENGTH] = '\0';
	szFunctionCode[FUNCTION_CODE_LENGTH] = '\0';
	szPUDLength[PUDLENGTH_LENGTH] = '\0';
	szSDUData[SDUDATA_LENGTH] = '\0';
	szCRC16[CRC16_LENGTH] = '\0';

	this->_parseUtil.intToBinary(this->destinationAddress, szDesAddress, ADDRESS_LENGTH);
	this->_parseUtil.intToBinary(this->sourceAddress, szSrcAddress, ADDRESS_LENGTH);
	this->_parseUtil.boolToBinary(this->isCompressed, szIsCompressed);
	this->_parseUtil.boolToBinary(this->isEncrypted, szIsEncrypted);
	this->_parseUtil.intToBinary(this->functionCode, szFunctionCode, FUNCTION_CODE_LENGTH);
	this->_parseUtil.intToBinary(this->PUDLength, szPUDLength, PUDLENGTH_LENGTH);
	this->sduDataBody.toBinaryDisplay(szSDUData);
	strcpy(szDataStringForCRC16, szDesAddress);
	strcat(szDataStringForCRC16, szSrcAddress);
	strcat(szDataStringForCRC16, szIsCompressed);
	strcat(szDataStringForCRC16, szIsEncrypted);
	strcat(szDataStringForCRC16, szFunctionCode);
	strcat(szDataStringForCRC16, szPUDLength);
	strcat(szDataStringForCRC16, this->sduDataBody.szFrameData);
	this->CRC16 = (int)this->_parseUtil.CRC16StringToUInt(szDataStringForCRC16, PUDDATA_LENGTH-CRC16_LENGTH);
	this->_parseUtil.unsignedIntToBinary(this->CRC16, szCRC16);
	
	szIsCompressed[BOOL_TYPE_SIZE] = '\0';
	szIsEncrypted[BOOL_TYPE_SIZE] = '\0';

	strcpy(szPUDDataDisplay, szDesAddress);
	strcat(szPUDDataDisplay, szSrcAddress);
	strcat(szPUDDataDisplay, szIsCompressed);
	strcat(szPUDDataDisplay, szIsEncrypted);
	strcat(szPUDDataDisplay, szFunctionCode);
	strcat(szPUDDataDisplay, szPUDLength);
	strcat(szPUDDataDisplay, szSDUData);
	strcat(szPUDDataDisplay, szCRC16);
	this->setFrame(szPUDDataDisplay);
}

void PUDData::setFrame(char* szFrameString)
{
	strcpy(this->szFrame, szFrameString);
}

void PUDData::getFrameField(int fieldNo, char* szFrameFieldString)
{
	int indexFieldSize[PUDDATA_FIELDS_COUNT] = {ADDRESS_LENGTH,
												ADDRESS_LENGTH,
												BOOL_TYPE_SIZE,
												BOOL_TYPE_SIZE,
												FUNCTION_CODE_LENGTH,
												PUDLENGTH_LENGTH,
												SDUDATA_LENGTH,
												CRC16_LENGTH
												};
	int indexFieldStart[PUDDATA_FIELDS_COUNT] = {0,
												ADDRESS_LENGTH,
												2*ADDRESS_LENGTH,
												2*ADDRESS_LENGTH+BOOL_TYPE_SIZE,
												2*(ADDRESS_LENGTH+BOOL_TYPE_SIZE),
												2*(ADDRESS_LENGTH+BOOL_TYPE_SIZE)+FUNCTION_CODE_LENGTH,
												2*(ADDRESS_LENGTH+BOOL_TYPE_SIZE)+FUNCTION_CODE_LENGTH+PUDLENGTH_LENGTH,
												2*(ADDRESS_LENGTH+BOOL_TYPE_SIZE)+FUNCTION_CODE_LENGTH+PUDLENGTH_LENGTH+SDUDATA_LENGTH,
												};
	_parseUtil.partitionFrameString(szFrameFieldString, indexFieldStart[fieldNo], indexFieldSize[fieldNo], this->szFrame);
}

void PUDData::setPropertiesFromFrameData()
{
	unsigned int receivedCRC16 = 0;
	char szDataStringForCRC16[PUDDATA_LENGTH-CRC16_LENGTH+1] = "";
	char szTmpDesAddress[ADDRESS_LENGTH+1] = "";
	char szTmpSrcAddress[ADDRESS_LENGTH+1] = "";
	char szTmpIsCompressed[BOOL_TYPE_SIZE+1] = "";
	char szTmpIsEncryted[BOOL_TYPE_SIZE+1] = "";
	char szTmpFunctionCode[FUNCTION_CODE_LENGTH+1] = "";
	char szTmpPUDDataLength[PUDLENGTH_LENGTH+1] = "";
	char szTmpSDUData[SDUDATA_LENGTH+1] = "";
	char szTmpCRC16[CRC16_LENGTH+1] = "";

	this->getFrameField(DES_ADDRESS_FIELD, szTmpDesAddress);
	this->getFrameField(SRC_ADDRESS_FIELD, szTmpSrcAddress);
	this->getFrameField(COMPRESS_FIELD, szTmpIsCompressed);
	this->getFrameField(ENCRYPT_FIELD, szTmpIsEncryted);
	this->getFrameField(FUNCTION_CODE_FIELD, szTmpFunctionCode);
	this->getFrameField(PUD_LENGTH_FIELD, szTmpPUDDataLength);
	this->getFrameField(SDU_DATA_FIELD, szTmpSDUData);
	this->getFrameField(CRC16_FIELD, szTmpCRC16);
	this->destinationAddress = this->_parseUtil.binaryToInt(szTmpDesAddress);
	this->sourceAddress = this->_parseUtil.binaryToInt(szTmpSrcAddress);
	this->isCompressed = this->_parseUtil.binaryToBool(szTmpIsCompressed);
	this->isEncrypted= this->_parseUtil.binaryToBool(szTmpIsEncryted);
	this->functionCode = this->_parseUtil.binaryToInt(szTmpFunctionCode);
	this->PUDLength = this->_parseUtil.binaryToInt(szTmpPUDDataLength);

	SDUData sduDataBody;
	this->getFrameField(SDU_DATA_FIELD, szTmpSDUData);
	sduDataBody.setFrame(szTmpSDUData);
	sduDataBody.setPropertiesFromFrameData();
	this->sduDataBody = sduDataBody;

	//CRC16 validation
	strcpy(szDataStringForCRC16, szTmpDesAddress);
	strcat(szDataStringForCRC16, szTmpSrcAddress);
	strcat(szDataStringForCRC16, szTmpIsCompressed);
	strcat(szDataStringForCRC16, szTmpIsEncryted);
	strcat(szDataStringForCRC16, szTmpFunctionCode);
	strcat(szDataStringForCRC16, szTmpPUDDataLength);
	strcat(szDataStringForCRC16, szTmpSDUData);
	this->CRC16 = this->_parseUtil.CRC16StringToUInt(szDataStringForCRC16, PUDDATA_LENGTH-CRC16_LENGTH);
	receivedCRC16 = this->_parseUtil.binaryToUnsignedInt(szTmpCRC16);
	if(this->CRC16==receivedCRC16)	this->isDataRightByCRC16=true;
	else							this->isDataRightByCRC16=false;
}

void PUDData::toBinaryData(char* szBinaryData)
{
	this->_parseUtil.binaryStrToBinaryData(this->szFrame, szBinaryData, BINARY_FRAME_SIZE);
}

void PUDData::setBinaryData(char* szBinaryData)
{
	char szFrameTmp[PUDDATA_LENGTH+1] = "";
	this->_parseUtil.binaryDataToBinaryStr(szBinaryData, szFrameTmp, BINARY_FRAME_SIZE);
	this->setFrame(szFrameTmp);
}